package com.yisu.auction.ewf.common.wechat;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.yisu.auction.ewf.common.enums.OAuthScope;
import com.yisu.auction.ewf.common.enums.WeChatReturnCode;
import com.yisu.auction.ewf.common.web.HttpWebClient;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * Created by hp2540p on 2016/12/31.
 */
public class WechatApi {
    public static WechatApi wechat = new WechatApi();

    //public static String AppID = "wx0848e6965d142f2e";
    //public static String AppSecret = "d4624c36b6795d1d99dcf0547af5443d";
    //public static String AppCallBackHost = "http://192.168.17.60:8080";
    //正式
    public static String AppID = "wxfe6c25d446435ead";
    public static String AppSecret = "6c4efdabee29dd546a1acd3cbb125c63";
    public static String AppCallBackHost = "http://weixin.hzyisu.com";
    //临时使用的随机验证码（用户授权模式）
    public static String TmpRandomState = "dyd01";
    //认证授权回调地址
    public static String AuthenticationCallBackHost = AppCallBackHost + "/wechat/UserInfoCallback";
    //静默跳转授权地址
    public static String SilenceCallBackHost = AppCallBackHost + "/wechat/BaseCallback";

    /// <summary>
    /// 获取凭证接口
    /// </summary>

    /// <param name="appid">第三方用户唯一凭证</param>
    /// <param name="secret">第三方用户唯一凭证密钥，既appsecret</param>
    /// <param name="grant_type">获取access_token填写client_credential</param>
    /// <returns></returns>
    public WxAccessTokenResult GetAppToken(String appid, String secret) throws UnsupportedEncodingException {
        String url = String.format("https://api.weixin.qq.com/cgi-bin/token?grant_type=%s&appid=%s&secret=%s",
                "client_credential", appid, secret);
        JSONObject obj = get1(url);//将json字符串转换为json对象
        WxAccessTokenResult result = new WxAccessTokenResult();
        result.setAccess_token(obj.getString("access_token"));
        result.setExpires_in(obj.getInteger("expires_in"));
        return result;
    }


    /// <summary>
    /// 获取微信服务器IP列表
    /// </summary>
    /// <param name="accessToken"></param>
    /// <returns></returns>
    public WxServerIpResult GetServerIp(String accessToken) throws UnsupportedEncodingException {
        String url = String.format("https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token=%s",
                accessToken);
        JSONObject obj = get1(url);//将json字符串转换为json对象
        WxServerIpResult result = new WxServerIpResult();
        //result.setIp_list(obj.getJSONArray("ip_list"));
        return result;

    }

    /// <summary>
    /// 【step1 / step2】获取授权验证地址
    /// <para> 这一步发送之后，客户会得到授权页面，无论同意或拒绝，都会返回redirectUrl页面。 </para>
    /// <para> 如果用户同意授权，页面将跳转至 redirect_uri/?code=CODE&amp;state=STATE。这里的code用于换取access_token（和通用接口的access_token不通用）</para>
    /// <para> 若用户禁止授权，则重定向后不会带上code参数，仅会带上state参数redirect_uri?state=STATE</para>
    /// </summary>
    /// <param name="appId"></param>
    /// <param name="redirectUrl">回调地址</param>
    /// <param name="state">临时使用的随机验证码,用于保持请求和回调的状态，授权请求后原样带回给第三方。该参数可用于防止csrf攻击（跨站请求伪造攻击），建议第三方带上该参数，可设置为简单的随机数加session进行校验.最多128字节</param>
    /// <param name="scope">应用授权作用域(简单授权snsapi_base | 弹出授权snsapi_userinfo)</param>
    /// <param name="responseType">返回类型，请填写code</param>
    /// <returns>跳转到微信的地址</returns>
    public String GetAuthorizeUrl(String appId, String redirectUrl, String state, OAuthScope scope) {
        String url = String.format("https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=%s&scope=%s&state=%s#wechat_redirect",
                appId, java.net.URLEncoder.encode(redirectUrl), "code", scope, state);

        // 如果用户同意授权，页面将跳转至 redirect_uri/?code=CODE&state=STATE。
        // 若用户禁止授权，则重定向后不会带上code参数，仅会带上state参数redirect_uri?state=STATE
        return url;
    }

    /// <summary>
    /// 【step2 / step2】根据授权的code票据，获取AccessToken
    /// <code>
    /// {
    /// "access_token":"ACCESS_TOKEN",
    ///  "expires_in":7200,
    ///  "refresh_token":"REFRESH_TOKEN",
    ///  "openid":"OPENID",
    ///  "scope":"SCOPE",
    ///  "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
    /// }
    /// </code>
    /// </summary>
    /// <param name="appId">公众号的唯一标识</param>
    /// <param name="secret">公众号的appsecret</param>
    /// <param name="code">code作为换取access_token的票据，每次用户授权带上的code将不一样，code只能使用一次，5分钟未被使用自动过期。</param>
    /// <param name="grantType">填写为authorization_code</param>
    /// <returns></returns>
    public WxOAuthAccessToken GetUserAccessToken(String appId, String secret, String code) throws UnsupportedEncodingException {
        String url = String.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=%s",
                appId, secret, code, "authorization_code");
        JSONObject obj = get1(url);//将json字符串转换为json对象
        //String name = obj.getString("name");
        //JSONObject obj = new JSONObject().fromObject(returnText);//将json字符串转换为json对象
        //WxOAuthAccessToken result = (WxOAuthAccessToken)JSONObject.toBean(obj, WxOAuthAccessToken.class);//将建json对象转换为Person对象
        WxOAuthAccessToken result = new WxOAuthAccessToken();
        result.setOpenid(obj.getString("openid"));
        result.setAccess_token(obj.getString("access_token"));
        result.setExpires_in(obj.getInteger("expires_in"));
        result.setScope(obj.getString("scope"));
        return result;
    }

    /// <summary>
    /// 刷新access_token（如果需要）
    /// 由于access_token拥有较短的有效期，当access_token超时后，可以使用refresh_token进行刷新，refresh_token拥有较长的有效期（7天、30天、60天、90天），当refresh_token失效的后，需要用户重新授权。
    /// </summary>
    /// <param name="appId"></param>
    /// <param name="refreshToken">填写通过access_token获取到的refresh_token参数</param>
    /// <param name="grantType">填写为refresh_token</param>
    /// <returns></returns>
    public WxOAuthAccessToken RefreshToken(String appId, String refreshToken) throws UnsupportedEncodingException {
        String url = String.format("https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=%s&grant_type=%s&refresh_token=%s",
                appId, "refresh_token", refreshToken);
        JSONObject obj = get1(url);//将json字符串转换为json对象
        WxOAuthAccessToken result = new WxOAuthAccessToken();
        result.setOpenid(obj.getString("openid"));
        result.setAccess_token(obj.getString("access_token"));
        result.setScope(obj.getString("scope"));
        return result;
    }

    /// <summary>
    /// 检验授权凭证（access_token）是否有效
    /// </summary>
    /// <param name="accessToken">网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同</param>
    /// <param name="openId"></param>
    /// <returns></returns>
    public boolean CheckToken(String accessToken, String openId) throws UnsupportedEncodingException {
        String url = String.format("https://api.weixin.qq.com/sns/auth?access_token=%s&openid=%s", accessToken, openId);

        // 正确时：{ "errcode":0,"errmsg":"ok"}
        // 错误时：{ "errcode":40003,"errmsg":"invalid openid"}
        WxJsonResult result = get1(url);
        return CheckIsSuccess(result);
    }

    public WxTicket getJsTicket(String accessToken) throws UnsupportedEncodingException {
        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=" + accessToken + "";
        JSONObject obj = get1(url);//将json字符串转换为json对象
        WxTicket result = new WxTicket();
        result.setErrcode(obj.getInteger("errcode"));
        result.setErrmsg(obj.getString("errmsg"));
        result.setTicket(obj.getString("ticket"));
        result.setExpires_in(obj.getInteger("expires_in"));
        return result;
    }

    //    private static String getUrl(){
//        HttpServletRequest request = ServletActionContext.getRequest();
//        StringBuffer requestUrl = request.getRequestURL();
//        String queryString = request.getQueryString();
//        String url = requestUrl +"?"+queryString;
//        return url;
//    }
    private String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    private String create_nonce_str() {
        return UUID.randomUUID().toString();
    }

    //获取自1970年以来的毫秒数同java的System.currentTimeMillis()
    public String UnixInter() {
        return String.valueOf(System.currentTimeMillis());//单位:毫秒
    }

    //获取自1970年以来的秒数
    private String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);//单位:秒
    }

    /**
     * 获取签名,参考示例:http://blog.csdn.net/gif_t_t/article/details/50774523
     * 确认签名算法正确，可用微信 JS 接口签名校验工具:http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 页面工具进行校验。
     *
     * @param jsticket
     * @param url      当前网页的URL，不包含#及其后面部分
     * @return
     */
    public WxTicketResponse getSignture(String jsticket, String url) {
        WxTicketResponse response = new WxTicketResponse();
//        if (string.IsNullOrWhiteSpace(url))
//            url = HttpContext.Current.Request.Url.ToString();
        response.setAppId(WechatApi.AppID);
        response.setTicket(jsticket);
        response.setTimestamps(create_timestamp());
        response.setNonceStr(create_nonce_str());

        //这里参数的顺序要按照 key 值 ASCII 码升序排序
        //注意这里参数名必须全部小写，且必须有序
        String rawstring = "jsapi_ticket=" + jsticket +
                "&noncestr=" + response.getNonceStr() +
                "&timestamp=" + response.getTimestamps() +
                "&url=" + url;
        String signature = "";
        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(rawstring.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        response.setSignature(signature);
        return response;
    }

    /// <summary>
    /// 获取授权用户信息
    /// </summary>
    /// <param name="accessToken">网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同</param>
    /// <param name="openId"></param>
    /// <param name="lang">返回国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语</param>
    /// <returns></returns>
    public WxOAuthUserInfo GetOAuthUserInfo(String accessToken, String openId) throws UnsupportedEncodingException {
        String url = String.format("https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=%s", accessToken, openId, "zh_CN");
        JSONObject obj = get1(url);//将json字符串转换为json对象
        WxOAuthUserInfo result = new WxOAuthUserInfo();
        result.setOpenid(obj.getString("openid"));
        result.setNickname(obj.getString("nickname"));
        result.setSex(obj.getInteger("sex"));
        result.setProvince(obj.getString("province"));
        result.setCity(obj.getString("city"));
        result.setCountry(obj.getString("country"));
        result.setHeadimgurl(obj.getString("headimgurl"));
        result.setUnionid(obj.getString("unionid"));
        result.setLanguage(obj.getString("language"));

        return result;
    }

    /// <summary>
    /// 获取用户基本信息(UnionID机制)
    /// </summary>
    /// <param name="accessToken"></param>
    /// <param name="openId"></param>
    /// <param name="lang"></param>
    /// <returns></returns>
    public WxUnionUserInfo GetUnionUserInfo(String accessToken, String openId) throws UnsupportedEncodingException {
        // lang:返回国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语
        String url = String.format("https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=%s", accessToken, openId, "zh_CN");
        JSONObject obj = get1(url);//将json字符串转换为json对象
        WxUnionUserInfo result = new WxUnionUserInfo();
        result.setUnionid(obj.getString("unionid"));
        result.setSubscribe(obj.getInteger("subscribe"));
        return result;
    }


    public boolean CheckIsSuccess(WxOAuthAccessToken result) {
        return result.errcode == null || result.errcode == "0" || result.errcode == WeChatReturnCode.SystemBusy.getIndex().toString();
    }

    public boolean CheckIsSuccess(WxJsonResult result) {
        return result.errcode == null || result.errcode == "0" || result.errcode == WeChatReturnCode.SystemBusy.getIndex().toString();
    }


    protected static Map<String, String> headerMap = new HashMap<>();

    protected String post(String url, String body) {
        String result = HttpWebClient.postJsonBody(url, headerMap, body);
        System.out.println("response: " + result);
        return result;
    }

    protected String get(String url) {
        String result = HttpWebClient.get(url, headerMap);
        System.out.println("response: " + result);
        return result;
    }

    protected <T> T get1(String url) throws UnsupportedEncodingException {
        // 微信公众号开发--获取用户信息中文乱码的解决方案 http://blog.csdn.net/frankcheng5143/article/details/51612550
        // 原始json
        String returnText = HttpWebClient.get(url, headerMap);
        //System.out.println("response: " + returnText);
        // 编码后的json
        String jsonResult = new String(returnText.getBytes("ISO-8859-1"), "UTF-8");
        // 返回业务实体
        T result = JSON.parseObject(jsonResult, new TypeReference<T>() {
        });

        return result;
    }

}
